package com.cuixichang.minimalism.core.security.config;

import com.cuixichang.minimalism.core.security.design.*;
import com.cuixichang.minimalism.core.security.filter.JwtSecurityAuthenticationFilter;
import com.cuixichang.minimalism.core.security.intercept.DynamicSecurityFilter;
import com.cuixichang.minimalism.core.security.web.MyAccessDeniedHandler;
import com.cuixichang.minimalism.core.security.web.MyAuthenticationEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.ObjectUtils;

import java.util.Objects;

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    @ConditionalOnMissingBean(JWTAnalysisDesign.class)
    public JWTAnalysisDesign jwtAnalysisDesign(){
        return new DefaultJWTAnalysisDesign();
    }

    @Autowired(required = false)
    private UserDetailsService userDetailsService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private FilterInvocationSecurityMetadataSource dynamicSecurityMetadataSource;
    @Autowired
    private AccessDecisionManager dynamicAccessDecisionManager;
    @Autowired
    private RuleDefinitionDesign ruleDefinitionDesign;

    /**
     * 不拦截资源,所有用户均可访问的资源
     */
    @Override
    public void configure(WebSecurity webSecurity) {
        if(Objects.nonNull(ruleDefinitionDesign)){
            String[] ignoreRegular = ruleDefinitionDesign.ignoreRegular();
            if(ignoreRegular != null)
                webSecurity.ignoring().antMatchers(ignoreRegular);
        }
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setHideUserNotFoundExceptions(false);
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
        if(!ObjectUtils.isEmpty(userDetailsService)){
            daoAuthenticationProvider.setUserDetailsService(userDetailsService);

        }
        auth.authenticationProvider(daoAuthenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeRequests().anyRequest().permitAll()
                //有动态权限配置时添加动态权限校验过滤器
                .and().addFilterBefore(new DynamicSecurityFilter(dynamicSecurityMetadataSource,
                        dynamicAccessDecisionManager), FilterSecurityInterceptor.class)
                .formLogin().disable();
        httpSecurity.exceptionHandling()
                .accessDeniedHandler(new MyAccessDeniedHandler())
                .authenticationEntryPoint(new MyAuthenticationEntryPoint())
                ;
        httpSecurity.addFilterBefore(new JwtSecurityAuthenticationFilter(jwtAnalysisDesign()), UsernamePasswordAuthenticationFilter.class);
        //无状态会话认证
        httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().csrf().disable();

    }
}
